/*
Kiwi Editor is a framework for building WYSIWYG web editors.
Copyright (C) 2011  Roosevelt de Lima Sardinha

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

Contact the author at roosevelt1@gmail.com (Roosevelt) 
*/

/**
 * Toolbox of the editor, where all the tools are avaiable to be used.
 * @author Roosevelt de Lima Sardinha
 * @constructor	
*/
function toolBox(id, properties)
{
	//initialize variables
	var thisObject = this;
	
	/**
	 * The workspace this toolbox belongs to.
	 * @type {Object}  
	 */
	this.workspace = properties.workspace;
	
	/**
	 * The object that contains the initial properties of the toolbox.
	 * @type {Object} 
	 */
	this.properties = properties;
	
	/**
	 * The id of the toolbox.
	 * @type {String}
	 */
	this.id = id;
	
	/**
	 * The list of tools this toolbox contains.
	 * @type {Array}
	 */
	this.toolList = [];
	
	/**
	 * The path of the CSS stylesheet file.
	 * @type {String}
	 */
	this.cssPath = this.properties.cssPath ? this.properties.cssPath : "css/boxes/toolBox.css";
	
	/**
	 * The title of this toolbox.
	 * @type {String}
	 */
	this.title = this.properties.title ? this.properties.title : 'Toolbox';
	
	/**
	 * The left coordinate of the toolbox.
	 * @type {Int}
	 */
	this.left = this.properties.left ? parseInt(this.properties.left) : 0;
	
	/**
	 * The top coordinate of the toolbox.
	 * @type {Int}
	 */ 
	this.top = this.properties.top ? parseInt(this.properties.top) : 0;
	
	/**
	 * The width of the toolbox.
	 * @type {Int}
	 */
	this.width = this.properties.width ? parseInt(this.properties.width) : 100;
	
	/**
	 * The height of the toolbox.
	 * @type {Int}
	 */
	this.height = this.properties.height ? parseInt(this.properties.height) : 400;

	/** 
	 * The id of the DOM node that contains this toolbox.
	 * @type {String}
	 */
	this.parentId = this.properties.parent;
	var parent = document.getElementById(this.parentId);

	
	//Events
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done when you drag the toolbox.
	 * @param {Int} x The left coordinate of the toolbox while dragging.
	 * @param {Int} y The top coordinate of the toolbox while dragging.
	 * @param {Object} toolBox The toolbox being dragged.
	 */
	this.onDrag = function(x,y, toolBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done when you drop the toolbox.
	 * @param {Int} x The left coordinate of the toolbox when dropped.
	 * @param {Int} y The top coordinate of the toolbox when dropped.
	 * @param {Object} toolBox The toolbox being dropped.
	 */
	this.onDrop = function(x,y, toolBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done when you start to resize the toolbox.
	 * @param {Int} width The width of the toolbox when you start to resize.
	 * @param {Int} height The height of the toolbox when you start to resize.
	 * @param {Object} toolBox The toolbox being resized.
	 */
	this.onBeforeResize = function(width, height, toolBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done during resize.
	 * @param {Int} width The width of the toolbox during resize.
	 * @param {Int} height The height of the toolbox during resize.
	 * @param {Object} toolBox The toolbox being resized.
	 */
	this.onResize = function(width, height, toolBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done after resize.
	 * @param {Int} width The width of the toolbox after resize.
	 * @param {Int} height The height of the toolbox after resize.
	 * @param {Object} toolBox The toolbox resized.
	 */
	this.onAfterResize = function(width, height, toolBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done when you remove this toolbox.
	 */
	this.onRemove = function(){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done when you restore the size of this toolbox.
	 * @param {Object} toolBox The toolbox the size was restored.
	 */
	this.onRestoreSize = function(toolBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Called when you add a tool to the toolbox.
	 * @param {Object} id The id of the tool.
	 * @param {Object} label The label of the tool.
	 * @param {Object} properties The properties object passed to the addTool method.
	 * @param {Object} toolBox The toolbox where the tool was added.
	 */
	this.onAddTool = function(id, label, properties, toolBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Called when removing all the tools of the toolbox
	 * @param {Object} toolBox This toolbox.
	 */
	this.onRemoveAllTools = function(toolBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Called when loading a profile.
	 * @param {Object} profile_id The id of the profile being loaded
	 * @param {Object} properties The properties of the tools in the profile, like hint, propertyBox and instructionBox.
	 * @param {Object} toolBox The toolbox where the profile is being loaded.
	 */
	this.onLoadProfile = function(profile_id, properties, toolBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what to do when dragging a tool.
	 * @param {Object} toolBox The toolbox from where the tool has been dragged.
	 */
	this.onDragTool = function(toolBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what to do when dropping a tool.
	 * @param {Object} toolBox The toolbox from where the tool has been dragged.
	 */
	this.onDropTool = function(toolBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what to do when the cursor is over a tool
	 * @param {Object} toolBox The toolbox that the tool belongs to.
	 */
	this.onMouseOverTool = function(toolBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what to do when clicking a tool.
	 * @param {Object} toolBox The toolbox that the tool belongs to.
	 */
	this.onClickTool = function(toolBox){};	
	
	/**
	 * <b>Event</b><br/>
	 * Defines what to do when the cursor leaves a tool.
	 * @param {Object} toolBox The toolbox that the tool belongs to.
	 */	
	this.onMouseOutTool = function(toolBox){};
	

	//gets the initial size and position of the object
	var iniLeft = parseInt(properties.left);
	var iniTop = parseInt(properties.top);
	var iniWidth = parseInt(properties.width);
	var iniHeight = parseInt(properties.height);

	//code for the divs: background of the object and the div where the user work	

	//create toolbox background
	var toolBoxBg = document.createElement('div');
	toolBoxBg.id = this.id + 'Bg';
	toolBoxBg.className = 'tool-box';
	toolBoxBg.style.borderWidth = "4px";
	toolBoxBg.style.position = 'absolute';
	toolBoxBg.style.left = this.left + 'px';
	toolBoxBg.style.top = this.top + 'px';
	toolBoxBg.style.width = this.width + 'px';
	toolBoxBg.style.height = this.height + 'px';	
	
	//create toolbox header	
	var toolBoxHeader = document.createElement('div');
	toolBoxHeader.id = this.id + 'Header';
	toolBoxHeader.className = 'tool-box-header';
	toolBoxHeader.innerHTML = this.title;
	toolBoxHeader.ondblclick = function() {	
		thisObject.setLeft(iniLeft);
		thisObject.setTop(iniTop);
		thisObject.setWidth(iniWidth);
		thisObject.setHeight(iniHeight);
		thisObject.onRestoreSize(thisObject);
	};

	//create table inside the toolbox
	var toolTable = document.createElement('table');
	toolTable.id = 'toolTable';
	toolTable.className = 'tool-table';
	toolTable.border = '0';
	
	/**
	 * Adds a tool to the toolbox.
	 * @param {String} id The id of the tool. The same name of the folder where the files corresponding to the tools are installed. 
	 * All the 3 files (.js, .css and .png) should have the same name as the folder.
	 * @param {String} label The label to be presented to the user.
	 * @param {Object} properties The properties to be passed for the tool. 
	 */
	this.addTool = function(id, label, properties)
	{
		// Adds the image of a tool  and the corresponding text to the toolBox
		// Possible properties are hint, instructionObject, instruction
		var toolIcon = document.createElement('img');
		toolIcon.className = 'tool-icon';
		toolIcon.src = APP_HOME + "js/tools/" + id + "/" + id + ".png";
		toolIcon.title = properties.hint;
		toolIcon.id = id;
		toolIcon.style.width ='25px';
		toolIcon.style.height = '25px';
		toolIcon.instructionBox = properties.instructionBox;
		toolIcon.propertyBox = properties.propertyBox;
		
		//Loading tool
		var documentHead = document.getElementsByTagName('head')[0];
		var script = document.createElement('script');
		script.type = 'text/javascript';
		var path = APP_HOME + "js/tools/" + id + "/" + id + ".js"
		script.src = path;
		documentHead.appendChild(script);
		
		var link = document.createElement('link');
		link.rel = "stylesheet";
		link.type="text/css";
		link.href= APP_HOME + "js/tools/" + id + "/" + id + ".css";
		documentHead.appendChild(link);

		toolIcon.name = id;

		toolIcon.onmouseover = function(){
			if (properties.instructionBox != null)
			{
				thisObject.workspace.getInstructionBoxById(properties.instructionBox).setInstruction(properties.help, false);
			}
			thisObject.onMouseOverTool(thisObject);
		}
		toolIcon.onmouseout = function(){
			if (properties.instructionBox != null)
			{
				thisObject.workspace.getInstructionBoxById(properties.instructionBox).clearInstruction();
			}
			thisObject.onMouseOutTool(thisObject);
		}
		toolIcon.onclick = function(){
			if (properties.instructionBox != null)
			{
				thisObject.workspace.getInstructionBoxById(properties.instructionBox).setInstruction(properties.help, true);
			}
			thisObject.onClickTool(thisObject);
		}		
		var row = toolTable.insertRow(-1);
		var cell = row.insertCell(-1);
		cell.className = 'tool-cell';
		var cell = row.insertCell(-1);
		cell.className = 'tool-text-cell';

		toolTable.rows[toolTable.rows.length - 1].cells[0].appendChild(toolIcon);

		toolTextNode = document.createTextNode(label);
		toolTable.rows[toolTable.rows.length - 1].cells[1].appendChild(toolTextNode);

		$('#' + this.id).resizable('option', 'minWidth', toolTable.offsetWidth + toolTable.offsetLeft);
		$('#' + this.id).resizable('option', 'minHeight', toolTable.offsetHeight + toolTable.offsetTop);
		
		// Makes the icon draggable.
		$('#' + toolIcon.id).draggable({
			revert: 'invalid',
			helper: 'clone',
			drag: function(event, ui){
				thisObject.onDragTool(thisObject);
			},
			stop: function(event, ui){
				thisObject.onDropTool(thisObject);
			}
		});	
		
		this.toolList.push(id);
		
		this.onAddTool(id, label, properties, this);
	}
	
	/**
	 * Removes all the tools in the toolbox and its corresponding scripts from the header.
	 */
	this.removeAllTools = function(){
		var documentHead = null;
		var script_tags = null;
		var link_tags = null;
		var num_rows =  toolTable.rows.length;
		for (var i = 0; i<num_rows; i++){
			toolTable.deleteRow(0);
		}
	
		documentHead = document.getElementsByTagName('head')[0];
		var toolId = "";
		var toolList_length = this.toolList.length;
		var script_tags_length = 0;
		var link_tags_length = 0;

		for (var i = 0; i < toolList_length; i++) {
			toolId = this.toolList[i];

			// Remove script tags
			script_tags = documentHead.getElementsByTagName('script');
			script_tags_length = script_tags.length;
			for (var j = 0; j < script_tags_length; j++){
				if (script_tags[j].src == (location.protocol + "//" + location.hostname + ":" + location.port + APP_HOME + "js/tools/" + toolId + "/" + toolId + ".js")){
					documentHead.removeChild(script_tags[j]);
					j--;
					script_tags_length--;
				} 
			}

			// Remove link tags
			link_tags = documentHead.getElementsByTagName('link');
			link_tags_length = link_tags.length; 
			for (var j = 0; j < link_tags_length; j++) {
				if (link_tags[j].href == (location.protocol + "//" + location.hostname + ":" + location.port + APP_HOME + "js/tools/" + toolId + "/" + toolId + ".css")) {
					documentHead.removeChild(link_tags[j]);
					j--;	
					link_tags_length--;
				}
			}
		}
		
		this.toolList = [];
		
		this.onRemoveAllTools(this);
	}
	
	/**
	 * Loads a profile in the toolbox.
	 * @param {String} profile_id The id of the profile to be loaded.
	 * @param {Object} properties The properties to be passed to the tools loaded.
	 * @return The loaded profile.
	 * @type {Object}
	 */
	this.loadProfile = function(profile_id, properties){
		var req = new request();
		req.sendSincRequest('GET', null, "profiles/" + profile_id, function(response){
			json_str = response;
		});
		json = JSON.parse(json_str);
		var types = json['type'];
		for (var i =0; i<types.length; i++){
			this.addTool(types[i], types[i], properties);	
		}
		
		this.onLoadProfile(profile_id, properties, this)
		
		return json;
	}
	
	//create toolbox
	var toolBox = document.createElement('div');
	/**
	 * @ignore
	 */
	toolBox.id = this.id;
	toolBox.style.position = 'absolute';
	toolBox.style.left = this.left + parseInt(toolBoxBg.style.borderLeftWidth) + 'px';
	toolBox.style.top = this.top + parseInt(toolBoxBg.style.borderTopWidth) + 'px';
	toolBox.style.width = this.width + 'px';
	toolBox.style.height = this.height + 'px';
	toolBox.appendChild(toolBoxHeader);
	toolBox.appendChild(toolTable);

	parent.appendChild(toolBoxBg);
	parent.appendChild(toolBox);

	var tableWidth = toolTable.offsetWidth + toolTable.offsetLeft;
	var tableHeight = toolTable.offsetHeight + toolTable.offsetTop;

	//makes toolbox resizable
	$('#' + this.id).resizable({
		start: function(event, ui){
			thisObject.onBeforeResize(document.getElementById(thisObject.id).offsetWidth, document.getElementById(thisObject.id).offsetHeight, thisObject);	
		},	
		resize: function(event,ui){
			thisObject.setWidth(document.getElementById(thisObject.id).offsetWidth);
			thisObject.setHeight(document.getElementById(thisObject.id).offsetHeight);
			thisObject.onResize(document.getElementById(thisObject.id).offsetWidth, document.getElementById(thisObject.id).offsetHeight, thisObject);
		},
		stop:  function(event,ui){
			thisObject.setWidth(document.getElementById(thisObject.id).offsetWidth);
			thisObject.setHeight(document.getElementById(thisObject.id).offsetHeight);
			thisObject.onAfterResize(document.getElementById(thisObject.id).offsetWidth, document.getElementById(thisObject.id).offsetHeight, thisObject);
		},
		containment:'#' + parent.id,
		minWidth: tableWidth, 
		minHeight: tableHeight
	});

	//makes toolbox draggable
	$('#' + this.id).draggable(
		{handle:'#' + this.id + 'Header',
		containment:'#' + parent.id,
		drag: function(event,ui){
			thisObject.setTop(document.getElementById(thisObject.id).offsetTop);
			thisObject.setLeft(document.getElementById(thisObject.id).offsetLeft);
			thisObject.onDrag(document.getElementById(thisObject.id).offsetLeft, document.getElementById(thisObject.id).offsetTop, thisObject);
			},

		stop: function(event,ui){
			thisObject.setTop(document.getElementById(thisObject.id).offsetTop);
			thisObject.setLeft(document.getElementById(thisObject.id).offsetLeft);
			thisObject.onDrop(document.getElementById(thisObject.id).offsetLeft, document.getElementById(thisObject.id).offsetTop, thisObject);
			}
		});

	/**
	 * Sets the left property of the toolbox. 
	 * @param {Int} left The left coordinate to be set.
	 */
	this.setLeft = function (left){
		toolBoxBg.style.left = left + 'px';
		if (navigator.appName != "Microsoft Internet Explorer")
		{	
			toolBox.style.left = left + parseInt(toolBoxBg.style.borderLeftWidth) + 'px';
		}
		else
		{
			toolBox.style.left = left + 'px';
		}
		this.left = left;	
	}	

	/**
	 * Sets the top property of the toolbox
	 * @param {Int} top The top coordinate to be set.
	 */
	this.setTop = function (top){
		toolBoxBg.style.top = top + 'px';
		if (navigator.appName != "Microsoft Internet Explorer")
		{
			toolBox.style.top = top + parseInt(toolBoxBg.style.borderTopWidth) + 'px';	
		}
		else
		{
			toolBox.style.top = top + 'px';	
		}
		this.top = top;
	}

	/**
	 * Sets the width of the toolbox.
	 * @param {Int} width The width to be set.
	 */
	this.setWidth = function (width){
		toolBoxBg.style.width = width + 'px';
		toolBox.style.width = width + 'px';	
		this.width = width;
	}	

	/**
	 * Sets the height of the toolbox.
	 * @param {Int} height The height to be set.
	 */
	this.setHeight = function (height){
		toolBoxBg.style.height = height + 'px';
		toolBox.style.height = height + 'px';	
		this.height = height;
	}			
	
	/**
	 * Sets the title of the toolbox. 
	 * @param {String} title The new title to be set.
	 */
	this.setTitle = function(title){
		toolBoxHeader.innerHTML = title;
		this.title = title;
	}

	/**
	 * Changes a property of the toolbox to some value
	 * @param {String} propertyName The name of the property to be changed.
	 * @param {Any} value The value to be set to the property.
	 */
	this.setProperty = function(propertyName, value){
		switch(propertyName){
			case 'height':
				this.setHeight(value);
				break;
			
			case 'width':
				this.setWidth(value);
				break;
				
			case 'top':
				this.setTop(value);
				break;
			
			case 'left':
				this.setLeft(value);
				break;
			
			case 'title':
				this.setTitle(value);
				break;

			case 'cssPath':
				this.setCSS(value);
				break;
			
			default:
				document.write('Property not found');
				break;
		}
	}

	this.setLeft(this.left);
	this.setTop(this.top);
	this.setWidth(this.width);
	this.setHeight(this.height);
	
	/**
	 * Removes this toolbox.
	 */
	this.remove = function(){
		this.removeAllTools()
		toolTable.parentNode.removeChild(toolTable); 
		toolBox.parentNode.removeChild(toolBox);
		toolBoxBg.parentNode.removeChild(toolBoxBg);
		toolBoxHeader.parentNode.removeChild(toolBoxHeader);
		delete toolBox;
		delete toolBoxBg;
		delete toolBoxHeader;
		this.onRemove();
	}
	
	/**
	 * Sets a new CSS stylesheet to the toolbox.
	 * @param {String} path The relative path of the CSS stylesheet file from the APP_HOME folder.
	 */
	this.setCSS = function(path){
		this.workspace.setCSS(this, path);
	}
	this.setCSS(this.cssPath);
}


